#include "view_font.h"
#include "lib_freetype_adapt.h"
#include <stdlib.h>

static int32_t _PrintBitMap(
    FtBitMap* map,
    bool isGrayMap,
    uint32_t color,
    int32_t x,
    int32_t y,
    ImageGrid& plane)
{
    /* bitMap数组计数 */
    int32_t mc = 0;
    /* plane的横纵坐标计数,偏移到有效区域 */
    int32_t py = y + map->bitTop;
    int32_t px;

    /* 颜色透明度分离 */
    uint32_t alpha = ((~color) >> 24) & 0xFF;
    if (isGrayMap)
        color &= 0xFFFFFF;

    for (int32_t cy = 0; cy < map->bitHeight; cy++, py++)
    {
        px = x + map->bitLeft;
        if (isGrayMap)
        {
            for (int32_t cx = 0; cx < map->lineByte; cx++, mc++, px++)
            {
                if (map->bitMap[mc])
                    plane.Write(px, py, ((~(alpha * map->bitMap[mc] / 0xFF)) << 24) | color);
            }
        }
        else
        {
            for (int32_t cx = 0; cx < map->lineByte; cx++, mc++, px++)
            {
                if (map->bitMap[mc])
                    plane.Write(px, py, color);
            }
        }
    }
    return 0;
}

static int32_t _PrintfBitMap(
    FtBitMap* map,
    bool isGrayMap,
    FILE* fp,
    char cPrint,
    char cEmpty)
{
    /* bitMap数组计数 */
    int32_t mc = 0;

    /* 上边空白 */
    for (int32_t y = map->bitTop; y > 0; y--)
    {
        for (int32_t x = 0; x < map->width; x++)
        {
            fputc(cEmpty, fp);
        }
        fputs("\r\n", fp);
    }

    for (int32_t y = 0; y < map->bitHeight; y++)
    {
        /* 左边空白 */
        for (int32_t x = 0; x < map->bitLeft; x++)
            fputc(cEmpty, fp);
        /* 中间内容 */
        if (isGrayMap)
        {
            for (int32_t x = 0; x < map->lineByte; x++, mc++)
            {
                if (map->bitMap[mc])
                    fputc(map->bitMap[mc] / 26 + '0', fp);
                else
                    fputc(cEmpty, fp);
            }
        }
        else
        {
            for (int32_t x = 0; x < map->lineByte; x++, mc++)
                if (map->bitMap[mc])
                    fputc(cPrint, fp);
                else
                    fputc(cEmpty, fp);
        }
        /* 右边空白 */
        for (int32_t x = map->width - map->bitLeft - map->bitWidth; x > 0; x--)
            fputc(cEmpty, fp);
        fputs("\r\n", fp);
    }

    /* 下边空白 */
    for (int32_t y = map->height - map->bitTop - map->bitHeight; y > 0; y--)
    {
        for (int32_t x = 0; x < map->width; x++)
        {
            fputc(cEmpty, fp);
        }
        fputs("\r\n", fp);
    }
    return 0;
}

/* ---------- ---------- ---------- */

ViewFont::ViewFont()
{
    m_ftHandle = NULL;
}

ViewFont::~ViewFont()
{
    if (m_ftHandle)
        LibFtRelease(m_ftHandle);
    m_ftHandle = NULL;
}

ViewFont* ViewFont::GetVF()
{
    static ViewFont* vf = NULL;
    if (!vf)
        vf = new ViewFont();
    return vf;
}

int32_t ViewFont::Load(ViewFontType id, const char* fontFile)
{
    if (!m_ftHandle)
        m_ftHandle = LibFtInit();
    if (!m_ftHandle)
        return -1;
    return LibFtAddFontFile(m_ftHandle, fontFile, (int32_t)id);
}

int32_t ViewFont::UnLoad()
{
    LibFtRelease(m_ftHandle);
    m_ftHandle = NULL;
    return 0;
}

int32_t ViewFont::SizeOf(
    const char* utf8,
    ViewFontType font,
    int32_t size,
    int32_t bold,
    int32_t spaceX,
    int32_t spaceY,
    int32_t lineLimit,
    int32_t degree,
    int32_t& retWidth,
    int32_t& retHeight)
{
    return LibFtGetSizeByUtf8(
        m_ftHandle,
        utf8,
        FT_GET_FONT(size, bold, (int32_t)font),
        spaceX,
        spaceY,
        lineLimit,
        degree,
        &retWidth,
        &retHeight);
}

int32_t ViewFont::Print(
    const char* utf8,
    ViewFontType font,
    int32_t size,
    int32_t bold,
    int32_t degree,
    bool isGrayMap,
    ImageGrid& plane,
    uint32_t color,
    int32_t x,
    int32_t y,
    int32_t spaceX,
    int32_t spaceY,
    bool autoEnter)
{
    int32_t _font = FT_GET_FONT(size, bold, (int32_t)font);
    FtBitMap map = {0};
    const char* p = utf8;

    int32_t cx = x;
    int32_t cy = y;

    if (!m_ftHandle)
        return -1;

    while (p && *p)
    {
        p = LibFtGetMapByUtf8(m_ftHandle, p, _font, degree, &map, true);
        if (!p)
            break;
        else if (!map.bitMap)
        {
            /* 特殊字符处理 */
            char sChar = *(p - 1);
            if (sChar == '\t')
                cx += size * VIEW_FONT_INTERVAL_TAB / 2;
            else if (sChar == '\n')
            {
                /* 重置横向偏移,纵向偏移增加 */
                cx = x;
                cy += size + spaceY;
                if (cy + spaceY > plane.Height())
                    break;
            }
        }
        else
        {
            /* 检查横向剩余位置 */
            if (cx + map.width > plane.Width() && autoEnter)
            {
                cx = x;
                cy += size + spaceY;
                if (cy + spaceY > plane.Height())
                    break;
            }

            _PrintBitMap(&map, isGrayMap, color, cx, cy, plane);

            /* 横向偏移 */
            cx += map.width + spaceX;
        }

        /* 横纵向出屏检查 */
        if (cx > plane.Width() && !autoEnter)
            break;
    }

    if (map.bitMap)
        free(map.bitMap);
    return 0;
}

int32_t ViewFont::Printf(
    const char* utf8,
    ViewFontType font,
    int32_t size,
    int32_t bold,
    int32_t degree,
    bool isGrayMap,
    FILE* fp,
    char cPrint,
    char cEmpty)
{
    int32_t _font = FT_GET_FONT(size, bold, (int32_t)font);
    FtBitMap map = {0};
    const char* p = utf8;

    if (!m_ftHandle || !fp)
        return -1;

    while (p && *p)
    {
        p = LibFtGetMapByUtf8(m_ftHandle, p, _font, degree, &map, true);
        if (!p)
            break;
        else if (!map.bitMap)
        {
            fprintf(fp, "addr: +%d, invisible char [%02X]\r\n",
                (int32_t)(p - utf8),
                *(p - 1));
            continue;
        }
        else
        {
            fprintf(fp, "addr: +%d, window: %dx%d, bitMap: %dx%d, left/top: %d,%d \r\n",
                (int32_t)(p - utf8),
                map.width, map.height,
                map.bitWidth, map.bitHeight,
                map.bitLeft, map.bitTop);
        }
        _PrintfBitMap(&map, isGrayMap, fp, cPrint, cEmpty);
    }

    if (map.bitMap)
        free(map.bitMap);
    return 0;
}
